package com.lyncs.ods.modules.txn.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.lyncs.ods.common.api.CommonPage;
import com.lyncs.ods.common.exception.ApiException;
import com.lyncs.ods.common.web.RequestHolder;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.modules.company.model.CompanyInfo;
import com.lyncs.ods.modules.company.service.CompanyInfoService;
import com.lyncs.ods.modules.company.service.CompanyUserRoleService;
import com.lyncs.ods.modules.msg.service.MessageService;
import com.lyncs.ods.modules.txn.model.*;
import com.lyncs.ods.modules.txn.service.*;
import com.lyncs.ods.modules.user.service.CompanyUserRelationService;
import com.lyncs.ods.req.ListPageSearchReq;
import com.lyncs.ods.req.SaveSettlementReq;
import com.lyncs.ods.resp.*;
import com.lyncs.ods.utils.PageUtil;
import com.lyncs.ods.utils.ParamCheckUtil;
import com.lyncs.ods.utils.TxnCommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author alex
 * @date 2022/3/10 14:19
 * @description
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class SettlementServiceImpl implements SettlementService {

    @Autowired
    private SettlementInfoService settlementInfoService;
    @Autowired
    private SettlementBillInfoService settlementBillInfoService;
    @Autowired
    private TxnFeeDetailService txnFeeDetailService;
    @Autowired
    private DeliverInfoService deliverInfoService;
    @Autowired
    private CompanyInfoService companyInfoService;
    @Autowired
    private CompanyUserRelationService companyUserRelationService;
    @Autowired
    private TxnOperateInfoService txnOperateInfoService;
    @Autowired
    private TxnEditLogService txnEditLogService;
    @Autowired
    private DeliverBillInfoService deliverBillInfoService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private CompanyUserRoleService companyUserRoleService;

    @Override
    public Long saveSettlement(SaveSettlementReq req) {
        ParamCheckUtil.checkTxnOptions(req);
        LocalDate dbDate = null;
        String dbName = null;
        SettlementInfo dbSettlementInfo = null;
        SettlementInfo settlementInfo = new SettlementInfo();
        if (req.getSettlementId() == null) {
            settlementInfo.setId(IdUtil.getSnowflakeNextId())
                    .setSellerId(req.getSellerId())
                    .setBuyerId(req.getBuyerId())
                    .setCreateTime(RequestHolder.getRequestDateTime())
                    .setCreator(RequestHolder.getUserId())
                    .setCreatorCompanyId(RequestHolder.getCompanyId())
                    .setStatus(LyncsOdsConstant.SettlementStatus.INIT.getKey());
        } else {
            //update
            dbSettlementInfo = settlementInfoService.getOneById(req.getSettlementId());
            BeanUtils.copyProperties(dbSettlementInfo, settlementInfo);
            dbDate = dbSettlementInfo.getStartDate();
            dbName = dbSettlementInfo.getSettlementName();
        }
        BigDecimal billAmount = req.getSettlementBillInfos().stream().map(SaveSettlementReq.DeliverSettleInfo::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalAmount = req.getDiscountInfo() == null || req.getDiscountInfo().getAmount() == null ? billAmount : billAmount.subtract(req.getDiscountInfo().getAmount());
        Function<List<SettlementInfo>, Map<Long, CompanyShortInfoResp>> companyInfoFunc = (list) -> companyInfoService.getTxnCompanyRespInfos(list);
        String settlementName = TxnCommonUtils.buildTicketName(
                settlementInfoService.lambdaQuery().setEntityClass(SettlementInfo.class).ne(SettlementInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey()),
                companyInfoFunc, LyncsOdsConstant.TxnType.SETTLEMENT, settlementInfo,
                req.getStartDate(), dbDate, req.getSettlementName(), dbName);
        settlementInfo.setSettlementName(settlementName)
                .setStartDate(req.getStartDate())
                .setTotalAmount(totalAmount)
                .setCategoryCount(req.getSettlementBillInfos().size())
                .setCurrency(req.getCurrency())
                .setLastUpdater(RequestHolder.getUserId())
                .setUpdateTime(RequestHolder.getRequestDateTime())
                .setDeadline(req.getDeadline() == null ? null : req.getDeadline().atTime(LocalTime.MIN))
                .setRemark(req.getRemark())
                .setPaymentTerms(req.getPaymentTerms())
                .setCertNo(req.getCertNo())
                .setDiscountInfo(req.getDiscountInfo() == null ? null : JSONObject.toJSONString(req.getDiscountInfo()))
                .setCustomFields(req.getCustomFields())
                .setAttachment(req.getAttachment());
        if (req.getOperateType() == 1) {
            settlementInfo.setStatus(LyncsOdsConstant.SettlementStatus.DRAFT.getKey());
        } else if (LyncsOdsConstant.OrderStatus.DRAFT.getKey().equals(settlementInfo.getStatus())) {
            settlementInfo.setStatus(LyncsOdsConstant.OrderStatus.INIT.getKey());
        }
        Long logId = IdUtil.getSnowflakeNextId();
        saveBillInfo(req, settlementInfo);
        settlementInfoService.saveOrUpdate(settlementInfo);
        txnEditLogService.saveLog(dbSettlementInfo, settlementInfo, LyncsOdsConstant.TxnType.SETTLEMENT, settlementInfo.getId(), logId, companyInfoService::getLoginCompanyName, companyUserRelationService::getLoginUserName);
        BiConsumer<CompanyInfo, CompanyInfo> emailNotifyFunc = (companyInfo, invitedCompanyInfo) -> messageService.shareTicketByEmail(req.getSettlementId() == null, LyncsOdsConstant.TxnType.ORDER, settlementInfo.getId(), companyInfo, invitedCompanyInfo, companyInfoService.getNotifyEmail(settlementInfo));
        BiConsumer<CompanyInfo, CompanyInfo> smsNotifyFunc = (companyInfo, invitedCompanyInfo) -> messageService.shareTicketBySms(req.getSettlementId() == null, LyncsOdsConstant.TxnType.ORDER, settlementInfo.getId(), companyInfo, invitedCompanyInfo.getId(), companyInfoService.getNotifyEmail(settlementInfo));
        Function<List<Long>, Map<Long, CompanyInfo>> companyFunc = (list) -> companyInfoService.getAvailableCompanyInfos(list).stream().collect(Collectors.toMap(CompanyInfo::getId, o -> o));
        TxnCommonUtils.notify(settlementInfo, companyFunc, emailNotifyFunc, smsNotifyFunc);
        return settlementInfo.getId();
    }

    private void saveBillInfo(SaveSettlementReq req, SettlementInfo settlementInfo) {
        List<SettlementBillInfo> billInfos = new ArrayList<>();
        if (req.getSettlementId() != null) {
            billInfos = settlementBillInfoService.lambdaQuery()
                    .eq(SettlementBillInfo::getSettlementId, settlementInfo.getId())
                    .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                    .list();
        }
        Map<Long, BigDecimal> deliverBillAmountMap = new HashMap<>();
        Triple<List<SettlementBillInfo>, List<Long>, List<SettlementBillInfo>> settlementBillDiff = TxnCommonUtils.getSettlementBillDiff(req.getSettlementBillInfos(), settlementInfo, billInfos, deliverBillAmountMap);
        //删除
        if (CollectionUtil.isNotEmpty(settlementBillDiff.getMiddle())) {
            settlementBillInfoService.lambdaUpdate()
                    .eq(SettlementBillInfo::getSettlementId, settlementInfo.getId())
                    .in(SettlementBillInfo::getDeliverBillId, settlementBillDiff.getMiddle())
                    .set(SettlementBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey())
                    .update();
        }
        //新增
        if (CollectionUtil.isNotEmpty(settlementBillDiff.getLeft())) {
            settlementBillInfoService.saveBatch(settlementBillDiff.getLeft());
        }
        //更新
        if (CollectionUtil.isNotEmpty(settlementBillDiff.getRight())) {
            settlementBillInfoService.updateBatchById(settlementBillDiff.getRight());
        }
    }

    @Override
    public CommonPage<SettlementPageResp> listSettlement(ListPageSearchReq req) {
        BiFunction<Long, Long, List<Long>> partnerFunc = (userId, companyId) -> companyUserRoleService.listAllAvailablePartnerId(userId, companyId);
        List<Long> topIdList = txnOperateInfoService.getTopTicket(RequestHolder.getCompanyId(), LyncsOdsConstant.TxnType.SETTLEMENT.getKey());
        LambdaQueryChainWrapper<SettlementInfo> wrapper = TxnCommonUtils.buildLambdaQueryWrapper(settlementInfoService.lambdaQuery().setEntityClass(SettlementInfo.class).ne(SettlementInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey()), req, partnerFunc);
        CommonPage<SettlementPageResp> commonPage = PageUtil.count(wrapper, req.getPage(), req.getPageSize());
        if (commonPage.getTotal() == 0) {
            return commonPage;
        }
        List<SettlementInfo> settlementInfos = wrapper.last(PageUtil.sortByUpdateTime(req.getPage(), req.getPageSize(), "id", topIdList)).list();
        Map<Long, CompanyShortInfoResp> txnCompanyRespInfoMap = companyInfoService.getTxnCompanyRespInfos(settlementInfos);
        Map<String, String> creatorNameMap = companyUserRelationService.getCompanyUserName(settlementInfos);

        Function<SettlementInfo, SettlementPageResp> convertFunc = (info) -> new SettlementPageResp()
                .setTop(topIdList.contains(info.getId()))
                .setId(info.getId())
                .setCreatorName(creatorNameMap.get(TxnCommonUtils.buildLong2StringKey(info.getCreatorCompanyId(), info.getCreator())))
                .setUpdateTime(info.getUpdateTime())
                .setSellerCompanyInfo(txnCompanyRespInfoMap.get(info.getSellerId()))
                .setBuyerCompanyInfo(txnCompanyRespInfoMap.get(info.getBuyerId()))
                .setCategoryCount(info.getCategoryCount())
                .setTotalAmount(info.getTotalAmount())
                .setStatus(info.getStatus())
                .setCurrency(info.getCurrency())
                .setCreatorCompanyId(info.getCreatorCompanyId());
        return PageUtil.result(settlementInfos, convertFunc, commonPage);
    }

    @Override
    public SettlementDetailInfoResp getSettlementDetail(Long settlementId) {
        SettlementInfo settlementInfo = settlementInfoService.getOneById(settlementId);
        List<SettlementBillInfo> settlementBillInfos = settlementBillInfoService.lambdaQuery()
                .eq(SettlementBillInfo::getSettlementId, settlementId)
                .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .list();

        Map<Long, List<Long>> deliverBillMap = settlementBillInfos.stream().distinct().collect(Collectors.groupingBy(SettlementBillInfo::getDeliverId, Collectors.mapping(SettlementBillInfo::getDeliverBillId, Collectors.toList())));
        List<DeliverInfo> deliverInfos = deliverInfoService.lambdaQuery().in(DeliverInfo::getId, deliverBillMap.keySet()).list();
        Map<Long, DeliverInfo> deliverInfoMap = deliverInfos.stream().collect(Collectors.toMap(DeliverInfo::getId, o -> o));
        List<TxnFeeDetail> txnFeeDetails = txnFeeDetailService.lambdaQuery()
                .in(TxnFeeDetail::getBillId, deliverBillMap.values().stream().flatMap(List::stream).collect(Collectors.toList()))
                .list();
        Map<Long, List<TxnFeeDetail>> billFeeNameMap = txnFeeDetails.stream().collect(Collectors.groupingBy(TxnFeeDetail::getBillId));

        Map<Long, CompanyShortInfoResp> txnCompanyInfoMap = TxnCommonUtils.buildTxnCompanyInfo((list) -> companyInfoService.getTxnCompanyRespInfos(list), settlementInfo);
        Long deliverCount = settlementBillInfos.stream().map(SettlementBillInfo::getDeliverId).filter(Objects::nonNull).distinct().count();
        return new SettlementDetailInfoResp(settlementInfo)
                .setRelatedDeliverCount(deliverCount)
                .setSellerCompanyInfo(txnCompanyInfoMap.get(settlementInfo.getSellerId()))
                .setBuyerCompanyInfo(txnCompanyInfoMap.get(settlementInfo.getBuyerId()))
                .setDiscountInfo(StringUtils.isNotEmpty(settlementInfo.getDiscountInfo()) ? JSONObject.parseObject(settlementInfo.getDiscountInfo(), SettlementDiscountInfo.class) : null)
                .setCreatorName(companyUserRelationService.getCompanyUserName(settlementInfo))
                .setTop(txnOperateInfoService.isTopTicket(RequestHolder.getCompanyIdAllowNull(), LyncsOdsConstant.TxnType.SETTLEMENT.getKey(), settlementInfo.getId()))
                .setSettlementBillInfos(settlementBillInfos.stream().map(bill -> {
                    List<TxnFeeDetail> thisTxnFeeDetails = billFeeNameMap.get(bill.getDeliverBillId());
                    DeliverInfo deliverInfo = deliverInfoMap.get(bill.getDeliverId());
                    return buildSettlementBillResp(deliverInfo, bill, thisTxnFeeDetails);
                }).collect(Collectors.toList()));
    }

    @Override
    public void reverseSettlement(Long settlementId) {
        settlementInfoService.lambdaUpdate()
                .eq(SettlementInfo::getId, settlementId)
                .set(SettlementInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .update();
        List<SettlementBillInfo> settlementBillInfos = settlementBillInfoService.lambdaQuery()
                .eq(SettlementBillInfo::getSettlementId, settlementId).list();
        settlementBillInfoService.lambdaUpdate()
                .in(SettlementBillInfo::getId, settlementBillInfos.stream().map(SettlementBillInfo::getId).collect(Collectors.toList()))
                .set(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .update();
        deliverInfoService.updateDeliveryStatus(settlementBillInfos.stream().map(SettlementBillInfo::getDeliverId).distinct().collect(Collectors.toList()));
    }

    @Override
    public void stickyOnTop(Long settlementId, Integer type) {
        txnOperateInfoService.saveTopTicket(LyncsOdsConstant.TxnType.SETTLEMENT, settlementId, type);
    }

    @Override
    public void updateStatus(Long settlementId, Integer status) {
        SettlementInfo settlementInfo = settlementInfoService.getOneById(settlementId);
        if (settlementInfo.getStatus().equals(status)) {
            return;
        }
        LambdaUpdateChainWrapper<SettlementInfo> updateChainWrapper = settlementInfoService.lambdaUpdate().eq(SettlementInfo::getId, settlementId).set(SettlementInfo::getStatus, status);
        if (LyncsOdsConstant.SettlementStatus.TO_BE_CONFIRMED.getKey().equals(status)) {
            updateChainWrapper.set(SettlementInfo::getLastPaymentTime, RequestHolder.getRequestDateTime());
        } else if (LyncsOdsConstant.SettlementStatus.CONFIRMED.getKey().equals(status)) {
            //推进交付单 && 交付账款状态
            List<SettlementBillInfo> settlementBillInfos = settlementBillInfoService.lambdaQuery()
                    .eq(SettlementBillInfo::getSettlementId, settlementId)
                    .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                    .list();
            if (CollectionUtils.isEmpty(settlementBillInfos)) {
                return;
            }
            Map<Long, BigDecimal> deliverBillMap = settlementBillInfos.stream().collect(Collectors.groupingBy(SettlementBillInfo::getDeliverBillId, Collectors.reducing(BigDecimal.ZERO, SettlementBillInfo::getAmount, BigDecimal::add)));
            List<DeliverBillInfo> deliverBillInfos = deliverBillInfoService.lambdaQuery().ne(DeliverBillInfo::getStatus, LyncsOdsConstant.DeliverStatus.DELETED.getKey()).in(DeliverBillInfo::getId, deliverBillMap.keySet()).list();
            List<DeliverBillInfo> updateBillList = deliverBillInfos.stream().filter(existBill -> deliverBillMap.containsKey(existBill.getId()))
                    .map(existBill -> {
                                BigDecimal bigDecimal = deliverBillMap.get(existBill.getId());
                                BigDecimal settledAmount = existBill.getSettledAmount().add(bigDecimal);
                                if (settledAmount.compareTo(existBill.getTotalAmount()) > 0) {
                                    throw new ApiException("请勿超量结算，交付单（" + existBill.getDeliverId() + "）的结算总额为" + existBill.getTotalAmount() + "，小于当前填写结算金额：" + bigDecimal);
                                }
                                Integer settleStatus = settledAmount.compareTo(BigDecimal.ZERO) == 0 ? LyncsOdsConstant.DeliverStatus.INIT.getKey() : settledAmount.compareTo(existBill.getTotalAmount()) < 0 ? LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey() : LyncsOdsConstant.DeliverStatus.SETTLED.getKey();
                                return new DeliverBillInfo()
                                        .setId(existBill.getId())
                                        .setDeliverId(existBill.getDeliverId())
                                        .setSettledAmount(settledAmount)
                                        .setStatus(settleStatus)
                                        .setUpdateTime(RequestHolder.getRequestDateTime());
                            }
                    ).collect(Collectors.toList());
            deliverBillInfoService.updateBatchById(updateBillList);
            deliverInfoService.updateDeliveryStatus(updateBillList.stream().map(DeliverBillInfo::getDeliverId).distinct().collect(Collectors.toList()));
        }
        updateChainWrapper.update();
    }

    @Override
    public CommonPage<UnsettledDeliveryBillResp> listUnsettledDelivery(Long sellerId, Long buyerId, String currency, Long deliverId, Integer page, Integer pageSize) {
        List<Integer> unsettledDeliveryStatus = List.of(LyncsOdsConstant.DeliverStatus.INIT.getKey(), LyncsOdsConstant.DeliverStatus.PARTIAL_SETTLEMENT.getKey());
        LambdaQueryChainWrapper<DeliverInfo> wrapper = deliverInfoService.lambdaQuery()
                .eq(DeliverInfo::getSellerId, sellerId)
                .eq(DeliverInfo::getBuyerId, buyerId)
                .eq(DeliverInfo::getCurrency, currency)
                .in(DeliverInfo::getStatus, unsettledDeliveryStatus);
        CommonPage<UnsettledDeliveryBillResp> commonPage = PageUtil.count(wrapper, page, pageSize);
        if (commonPage.getTotal() == 0) {
            return commonPage;
        }

        List<DeliverInfo> deliverInfos = wrapper.last(PageUtil.getLastSql(page, pageSize, "id", deliverId)).list();
        Map<Long, DeliverInfo> deliverMap = deliverInfos.stream().collect(Collectors.toMap(DeliverInfo::getId, o -> o));

        List<DeliverBillInfo> deliverBillInfos = deliverBillInfoService.lambdaQuery()
                .in(DeliverBillInfo::getDeliverId, deliverMap.keySet())
                .in(DeliverBillInfo::getStatus, unsettledDeliveryStatus)
                .list();

        List<Long> billIds = deliverBillInfos.stream().map(DeliverBillInfo::getId).collect(Collectors.toList());

        List<TxnFeeDetail> feeDetails = txnFeeDetailService.lambdaQuery()
                .in(TxnFeeDetail::getBillId, billIds)
                .in(TxnFeeDetail::getStatus, LyncsOdsConstant.EnableStatus.ENABLE.getKey())
                .list();

        Map<Long, List<TxnFeeDetail>> billFeeMap = feeDetails.stream().collect(Collectors.groupingBy(TxnFeeDetail::getBillId));
        Function<DeliverBillInfo, UnsettledDeliveryBillResp> func = (bill) -> {
            List<TxnFeeDetail> billFees = billFeeMap.get(bill.getId());
            DeliverInfo deliverInfo = deliverMap.get(bill.getDeliverId());
            return new UnsettledDeliveryBillResp()
                    .setName(TxnCommonUtils.buildDeliverBillName(deliverInfo))
                    .setSelected(bill.getDeliverId().equals(deliverId))
                    .setDeliverId(bill.getDeliverId())
                    .setDeliverName(deliverInfo.getDeliverName())
                    .setStatus(bill.getStatus())
                    .setBillId(bill.getId())
                    .setTotalAmount(bill.getTotalAmount())
                    .setSettledAmount(bill.getSettledAmount())
                    .setUnsettledAmount(bill.getTotalAmount().subtract(bill.getSettledAmount()))
                    .setCreateTime(bill.getCreateTime())
                    .setCurrency(bill.getCurrency())
                    .setFeeInfos(billFees.stream().map(fee -> {
                        UnsettledDeliveryBillResp.BillFeeInfo billFeeInfo = new UnsettledDeliveryBillResp.BillFeeInfo();
                        BeanUtils.copyProperties(fee, billFeeInfo);
                        return billFeeInfo;
                    }).collect(Collectors.toList()));

        };
        return PageUtil.result(deliverBillInfos, func, commonPage, UnsettledDeliveryBillResp::getDeliverId);
    }

    @Override
    public SettlementBillLogResp getBillSettleLog(Long billId, Long settlementId) {
        SettlementBillLogResp resp = new SettlementBillLogResp();
        if (Objects.isNull(billId) && Objects.isNull(settlementId)) {
            return resp;
        }
        SettlementInfo settlementInfo = settlementInfoService.getOneById(settlementId);
        List<SettlementBillInfo> settlementBillInfos = settlementBillInfoService.lambdaQuery()
                .eq(SettlementBillInfo::getSettlementId, settlementId)
                .eq(Objects.nonNull(billId), SettlementBillInfo::getDeliverBillId, billId)
                .ne(SettlementBillInfo::getStatus, LyncsOdsConstant.SettlementStatus.DELETED.getKey())
                .list();
        if (CollectionUtils.isEmpty(settlementBillInfos)) {
            return resp;
        }
        List<Long> deliverIds = settlementBillInfos.stream().map(SettlementBillInfo::getDeliverId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<DeliverInfo> deliverInfos = deliverInfoService.listByIds(deliverIds);
        Map<Long, String> deliverNameMap = deliverInfos.stream().collect(Collectors.toMap(DeliverInfo::getId, DeliverInfo::getDeliverName));
        Map<Long, CompanyShortInfoResp> txnCompanyInfoMap = TxnCommonUtils.buildTxnCompanyInfo((list) -> companyInfoService.getTxnCompanyRespInfos(list), settlementInfo);
        //结算历史统一取买方信息
        resp.setCompanyInfo(txnCompanyInfoMap.get(settlementInfo.getBuyerId()))
                .setSettleTime(settlementInfo.getStartDate())
                .setDeliverInfos(settlementBillInfos.stream().map(bill -> new SettlementBillLogResp.SettlementDeliverInfo()
                                .setDeliverId(bill.getDeliverId())
                                .setDeliverName(deliverNameMap.get(bill.getDeliverId()))
                                .setDeliverAmount(bill.getAmount())
                                .setTagInfos(JSONArray.parseArray(bill.getTagInfo(), TagInfo.class))
                        ).collect(Collectors.toList())
                );
        if (Objects.isNull(billId)) {
            return resp;
        }

        SettlementBillInfo settlementBillInfo = settlementBillInfos.get(0);
        DeliverInfo deliverInfo = deliverInfoService.getOneById(settlementBillInfo.getDeliverId());

        List<TxnFeeDetail> txnFeeDetails = txnFeeDetailService.lambdaQuery().eq(TxnFeeDetail::getBillId, settlementBillInfo.getDeliverBillId()).list();

        return resp.setDeliverBillLog(buildSettlementBillResp(deliverInfo, settlementBillInfo, txnFeeDetails));
    }

    @Override
    public CommonPage<TxnEditLogResp> getSettlementEditLog(Long settlementId, Integer page, Integer pageSize) {
        return txnEditLogService.getEditLog(LyncsOdsConstant.TxnType.SETTLEMENT.getKey(), settlementId, page, pageSize);
    }


    private SettlementBillResp buildSettlementBillResp(DeliverInfo deliverInfo, SettlementBillInfo settlementBillInfo, List<TxnFeeDetail> txnFeeDetails) {
        return new SettlementBillResp()
                .setName(TxnCommonUtils.buildDeliverBillName(deliverInfo))
                .setBillId(settlementBillInfo.getDeliverBillId())
                .setDeliverId(settlementBillInfo.getDeliverId())
                .setDeliverName(deliverInfo.getDeliverName())
                .setAmount(settlementBillInfo.getAmount())
                .setRemark(settlementBillInfo.getRemark())
                .setTagInfos(JSONArray.parseArray(settlementBillInfo.getTagInfo(), TagInfo.class))
                .setFeeInfos(txnFeeDetails.stream().map(fee -> new SettlementBillResp.FeeInfo().setFeeName(fee.getFeeName()).setRemark(fee.getRemark()).setAmount(fee.getFeeAmount())).collect(Collectors.toList()));
    }
}
